package server.common.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.concurrent.ScheduledFuture;
import server.common.message.NettyMessage;
import server.common.message.NettyMessageFactory;
import server.test.NettyClient;

import java.util.concurrent.TimeUnit;

/**
 * Created by xiangliyou on 17-9-23.
 * <p>
 * 握手成功后，客户端主动发送心跳消息，服务端收到心跳消息后返回心跳应答
 *
 * @DESCRIPTION 客户端发送心跳请求
 */
public class HeartBeatReqHandler extends SimpleChannelInboundHandler {

    private NettyClient client;
    //心跳次数计数
    private int heartbeatCount = 0;
    private volatile ScheduledFuture heartBeat;

    public HeartBeatReqHandler(NettyClient client) {
        this.client = client;
    }


    private class HeartBeatTask implements Runnable{

        private final ChannelHandlerContext ctx;

        public HeartBeatTask(ChannelHandlerContext ctx) {
            this.ctx = ctx;
        }

        @Override
        public void run() {
            //ctx.writeAndFlush(NettyMessageFactory.buildHeartBag())
            handleAllIdle(ctx);
        }
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        NettyMessage message = (NettyMessage) msg;
        if (message == null) {
            return;
        }

        //握手成功，开始发送心跳包
        if ((byte)(message.getBody()) == NettyMessageFactory.MESSAGE_TYPE_LOGIN_AUTH_RESULT_SUCCESS) {
            heartBeat = ctx.executor().scheduleAtFixedRate(new HeartBeatTask(ctx), 0, 3000, TimeUnit.MILLISECONDS);
        }else if (message.getHeader().getType() == NettyMessageFactory.PONG_MSG) {
            //收到服务端回复
            System.out.println("Client get pong msg from " + ctx.channel().remoteAddress());
        } else {
            ctx.fireChannelRead(msg);
        }
    }

    private void handleAllIdle(ChannelHandlerContext ctx) {
        //在读写通道超时时发送一个心跳包
        ctx.writeAndFlush(NettyMessageFactory.buildHeartBag(NettyMessageFactory.PING_MSG, heartbeatCount));
        heartbeatCount ++;
        System.out.println("Send Ping. count=" + heartbeatCount);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        //在传输通道闲置，不可用时重新连接服务端
        client.doConnect();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (heartBeat != null) {
            heartBeat.cancel(true);
            heartBeat = null;
        }

        ctx.fireExceptionCaught(cause);
    }
}
